package main

import (
	"fmt"
	"unsafe"
)

func shizhi() {
	// string在go看来本身是一个结构体
	// type string struct {
	// 	Data uintptr // 指针占8个字节
	// 	Len  int     // 长度64位系统占8个字节
	// }

	/**这也就解释了以下代码中，string类型的长度永远都是16 */
	fmt.Println(unsafe.Sizeof("happy"))                         // 16
	fmt.Println(unsafe.Sizeof("happy happy happy happy happy")) // 16
}

func main() {
	// string底层是一个bytes数组，因此数组也可以进行切片处理
	// string类型也是切片，但是内部仍为值类型
	/**
	单字母：1字节
	中文：3字节
	*/
	str1 := "hello@qq.com"
	slice := str1[6:]
	fmt.Println("str:", slice)

	// string本质
	shizhi()

	// string是不可变的，因为其内部为值类型，如果想改变string的值则需要先转为bytes类型
	arr1 := []byte(str1)
	arr1[0] = 'z'
	strByte := string(arr1)
	fmt.Println("strByte:", strByte)

	// 如果想支持中文，则需要使用rune()
	// 原因为[]byte字节处理，而一个汉字是三个字节，因此会出现乱码
	str2 := "宝宝@qq.com"
	arr2 := []rune(str2)
	arr2[1] = '贝'
	str2Byte := string(arr2)
	fmt.Println("str2Byte:", str2Byte)

	// 字符串遍历
	var str3 string = "hello, 中国!"
	for i := 0; i < len(str3); i++ {
		fmt.Println("str3字符串对应每个字符的编码:", str3[i])
		fmt.Println("str3字符串对应每个字符的字符串显示:", string(str3[i]))
	}

	// go语言类型转换和类型断言有什么区别，我们先看一个示例
	// 类型断言：从一个不确认性的具体类型（如示例中的interface{}）转换为一个确认的类型（如示例中的int类型），这个过程就是类型断言
	// 我们甚至可以使用其返回值判断类型断言是否成功
	var i interface{} = 2
	var param1 int = i.(int)
	fmt.Println("类型断言param1 value:", param1)

	params2, ok := i.(int)
	if ok {
		fmt.Println("类型断言param2 value:", params2)
	} else {
		fmt.Println("类型断言param2 断言失败...")
	}

	switch i.(type) {
	case string:
		fmt.Println("type of string")
	case int:
		fmt.Println("type of int")
	default:
		fmt.Println("unknown type")
	}

	// 类型转换：不同具体的类型进行转换的过程（ps：不是所有的类型都可以互相转换，需要进行类型兼容才行，另外当高精度转低精度类型时，可能会产生精度损耗或溢出问题）
	var f float64 = 12
	var param3 int = int(f)
	fmt.Println("类型转换param3 value:", param3)
}
